﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using log4net;
using LumenWorks.Framework.IO.Csv;
using Snap.Model;
using System.Linq;

namespace SnapInitializer
{
	class Program
	{
		private static readonly ILog Logger =
			(LogManager.GetLogger( System.Reflection.MethodBase.GetCurrentMethod().DeclaringType ));

		public static readonly string NYSE = "NYSE";
		public static readonly string NASDAQ = "NASDAQ";
		public static readonly string AMEX = "AMEX";

		static void Main()
		{
			Logger.Debug( "Program started" );

			Logger.Debug( "Initializing Database..." );
			InitializeData();
			Logger.Debug( "Initializing Complete." );
		}

		#region Initialize Data

		private static void InitializeData()
		{
			var context = new SnapModelContainer();

			// This can only be done if there are no news items associated with companies
			if (context.NewsToCompanies.Count() > 0)
			{
				throw new Exception( "Cannot initialize data: News items exist." );
			}

			// Delete all companies.
			var companyQuery = from c in context.Companies select c;
			foreach (var company in companyQuery)
			{
				context.Companies.DeleteObject( company );
			}
			context.SaveChanges();

			// Delete all Exchanges
			var exchangeQuery = from e in context.Exchanges select e;
			foreach (var exchange in exchangeQuery)
			{
				context.Exchanges.DeleteObject( exchange );
			}
			context.SaveChanges();

			// Add exchanges
			context.Exchanges.AddObject( new Exchange { Name = NASDAQ } );
			context.Exchanges.AddObject( new Exchange { Name = NYSE } );
			context.Exchanges.AddObject( new Exchange { Name = AMEX } );

			// Get Companies
			var fileLocations = DownloadDataFiles();
			var companies = ParseFiles( fileLocations );
		    var russellSymbols = ParseRussellFile( Properties.Settings.Default.RussellFileLocation );

			// Add companies to context
			foreach (var company in companies)
			{
                // Set flag for Russell 1k
			    if (russellSymbols.ContainsKey( company.Symbol ))
			    {
			        company.IsRussell1000 = true;
			    }
				context.Companies.AddObject( company );
			}
			context.SaveChanges();
		}

	    /// <summary>
		/// Downloads the data files into temp directory.
		/// </summary>
		/// <returns></returns>
		private static Dictionary<string, string> DownloadDataFiles()
		{
			var client = new WebClient();
			string tempDirectory = Properties.Settings.Default.TempDirectory;
			var fileLocations = new Dictionary<string, string>();

			// NASDAQ
			string nasdaqFileLocation = tempDirectory + "\\nasdaqCompanies.csv";
			client.DownloadFile( Properties.Settings.Default.NasdaqFileUrl, nasdaqFileLocation );
			fileLocations.Add( NASDAQ, nasdaqFileLocation );
			// NYSE
			string nyseFileLocation = tempDirectory + "\\nyseCompanies.csv";
			client.DownloadFile( Properties.Settings.Default.NyseFileUrl, nyseFileLocation );
			fileLocations.Add( NYSE, nyseFileLocation );
			// AMEX
			string amexFileLocation = tempDirectory + "\\amexCompanies.csv";
			client.DownloadFile( Properties.Settings.Default.AmexFileUrl, amexFileLocation );
			fileLocations.Add( AMEX, amexFileLocation );

			return (fileLocations);
		}

		private static IEnumerable<Company> ParseFiles( Dictionary<string, string> fileLocations )
		{
			var companies = new List<Company>();
			foreach (var exchange in fileLocations.Keys)
			{
				using (var csvReader = new CsvReader( new StreamReader( fileLocations[exchange] ), true ))
				{
					while (csvReader.ReadNextRecord())
					{
						var company = new Company
						{
							ExchangeName = exchange,
							Symbol = csvReader[0],
							Name = csvReader[1],
							LastSale = csvReader[2].Equals( "n/a" ) ? null : (Decimal?)Decimal.Parse( csvReader[2] ),
							MarketCap = csvReader[3].Equals( "n/a" ) ? null : (Decimal?)Decimal.Parse( csvReader[3] ),
							IpoYear = csvReader[4].Equals( "n/a" ) ? null : (int?)Int32.Parse( csvReader[4] ),
							Sector = csvReader[5].Equals( "n/a" ) ? null : csvReader[5],
							Industry = csvReader[6].Equals( "n/a" ) ? null : csvReader[6],
							SummaryQuoteUrl = csvReader[7]
						};
						companies.Add( company );
					}
				}
			}

            // Clean symbols
		    foreach (var company in companies)
		    {
		        string symbol = company.Symbol.TrimEnd().TrimStart();

                // Strip off ending ^
                if (symbol.EndsWith( "^" ))
		        {
                    company.Symbol = symbol.Substring( 0, symbol.Length - 1 );
		        }

                // Replace internal ^ with .
		        if (symbol.Contains( "^" ))
		        {
		            company.Symbol = symbol.Replace( "^", "." );
		        }

                // Replace internal / with .
                if(symbol.Contains( "/" ))
                {
                    company.Symbol = symbol.Replace( "/", "." );
                }
		    }

			return (companies);
		}

        private static IDictionary<string, string> ParseRussellFile( string pathToRussellFile )
        {
            var returnMap = new Dictionary<string, string>();
            var lines = File.ReadAllLines( pathToRussellFile );
            foreach (var line in lines)
            {
                string trimmedLine = line.TrimEnd();
                int length = trimmedLine.Length;
                int lastSpaceIndex = trimmedLine.LastIndexOf(" ");
                string symbol = trimmedLine.Substring(lastSpaceIndex + 1, length - (lastSpaceIndex + 1));
                returnMap[symbol] = symbol;
            }

            return returnMap;
        }

		#endregion Initialize Data

	}
}
